package middleware

import (
	"gin-epg/internal/app/leveldb"
	"time"
)

import (
	"context"
	"encoding/json"
	"github.com/google/uuid"
	"google.golang.org/grpc"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"
)

const (
	TokenPrefixKey         = "token:"
	UserPrefixKey          = "user:"
	SingleUserMaxTokenSize = 10
	defaultExpirationTime  = 1209600 // 2 weeks in seconds
)

type LeveldbSimpleTokenOperator struct {
	expirationTimeInSecond int64
	client                 leveldb.LevelDBServiceClient
}

func NewLeveldbSimpleTokenOperator(addr string, expirationTimeInSecond ...int64) (*LeveldbSimpleTokenOperator, error) {
	conn, err := grpc.Dial(addr, grpc.WithInsecure())
	if err != nil {
		return nil, err
	}
	expiration := defaultExpirationTime
	if len(expirationTimeInSecond) > 0 {
		expiration = int(expirationTimeInSecond[0])
	}
	client := leveldb.NewLevelDBServiceClient(conn)
	return &LeveldbSimpleTokenOperator{
		expirationTimeInSecond: int64(expiration),
		client:                 client,
	}, nil
}

// getUserMapFromToken 从 token 中获取 UserMap
func (r *LeveldbSimpleTokenOperator) getUserMapFromToken(token string) (map[string]interface{}, error) {
	key := TokenPrefixKey + token
	resp, err := r.client.Get(context.Background(), &leveldb.GetRequest{Key: key})
	if err != nil {
		if status.Code(err) == codes.NotFound {
			return nil, nil
		}
		return nil, err
	}
	var userMap map[string]interface{}
	err = json.Unmarshal([]byte(resp.Value), &userMap)
	if err != nil {
		return nil, err
	}
	return userMap, nil
}

// getExpirationDateFromToken 从 token 中获取过期日
func (r *LeveldbSimpleTokenOperator) getExpirationDateFromToken(token string) (time.Time, error) {
	resp, err := r.client.GetTTL(context.Background(), &leveldb.GetTTLRequest{Key: token})
	if err != nil {
		return time.Time{}, err
	}
	return time.Now().Add(time.Duration(resp.Ttl) * time.Second), nil
}

// isTokenExpired 判断 token 是否过期
func (r *LeveldbSimpleTokenOperator) isTokenExpired(token string) (bool, error) {
	key := TokenPrefixKey + token
	resp, err := r.client.Has(context.Background(), &leveldb.HasRequest{Key: key})
	if err != nil {
		return false, err
	}
	return !resp.Exists, nil
}

// generateToken 生成 token
func (r *LeveldbSimpleTokenOperator) generateToken(userMap map[string]interface{}) (string, error) {
	token := uuid.New().String()
	key := TokenPrefixKey + token
	value, err := json.Marshal(userMap)
	if err != nil {
		return "", err
	}
	_, err = r.client.Put(context.Background(), &leveldb.PutRequest{Key: key, Value: string(value), Ttl: r.expirationTimeInSecond})
	if err != nil {
		return "", err
	}
	return token, nil
}

// validateToken 判断 token 是否有效
func (r *LeveldbSimpleTokenOperator) validateToken(token string) (bool, error) {
	isExpired, err := r.isTokenExpired(token)
	if err != nil {
		return false, err
	}
	return !isExpired, nil
}

// 删除token
func (r *LeveldbSimpleTokenOperator) deleteToken(token string) error {
	key := TokenPrefixKey + token
	_, err := r.client.Delete(context.Background(), &leveldb.DeleteRequest{Key: key})
	return err
}
